#ifndef __BLOCKING_QUEUE_H_
#define __BLOCKING_QUEUE_H_

#include "Mutex.h"
#include "Condition.h"

#include <deque>

using namespace std;

template<typename T>
class BlockingQueue
{
public:
	void SetMaxSize(uint size)
	{
		_size = size;
	}
	
public:
	BlockingQueue()
	    :_lock(),
      notEmpty(_lock),
      _queue()
	{
		_size = 0;
	}
	
	bool Push(const T& x)
	{
		if ( _size == 0 ) //no bounds
		{
 			_push( x );
    	return true;
		}
		else
		{
			AutoLock lock(_lock);
			if ( _queue.size() == _size )
			{
				return false;
			}
			else
			{
    		_push( x );
    		return true;
			}
		}

	}
	
	T Pop()
  {
    AutoLock lock(_lock);
    while (_queue.empty())
    {
      _notEmpty.Wait();
    }
    
    T front(_queue.front());
    _queue.pop_front();
    return front;
  }
  
  size_t size() const
  {
   	AutoLock lock(_lock);
    return _queue.size();
  }
	
private:
	uint _size;

  mutable MutexLock _lock;
  Condition         _notEmpty;
  deque<T>     			_queue;
  
  void _push(const T& x)
 	{
 		AutoLock lock(_lock);
   	_queue.push_back(x);
   	_notEmpty.Signal(); // TODO: move outside of lock
 	}
	
};

#endif 